/*
 * DSBDirect
 * Copyright (C) 2019 Fynn Godau
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * This software is not affiliated with heinekingmedia GmbH, the
 * developer of the DSB platform.
 */

package godau.fynn.dsbdirect.table.reader;

import android.content.Context;
import android.util.Log;
import android.util.Xml;
import godau.fynn.dsbdirect.table.Entry;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;

public class Untis4 extends Reader {

    // Called Untis4 because it only works when there are four columns.

    /*
     * Let me help you understand the mess I created.
     *
     * Everything important (except for the "11.6.2018 Montag (Seite 1 / 4)", that is the only thing
     * in the whole file that is in a <div> tag) is with in a <td> tag within a <tr> tag. Every
     * <div> tag is used to read out the date which is marked within the table. Whenever a <td> tag
     * follows a <tr> tag, write mode is started. Whenever a </tr> tag follows a </td> tag, write
     * mode is stopped (a new line is also added).
     *
     * The interpreter creates an Entry every time there are four lines that are not blank within a
     * row as that is only the case with entries. The date marker is used to provide the date for
     * entries.
     *
     * <3
     *
     */

    private static final String DATEMARKER = "DATEMARKER::";
    private ArrayList<String> mTableStrings = new ArrayList<>();

    private XmlPullParser mParser;

    public Untis4(String html, Context context) {
        super(html, context);

        html = html.replaceAll("<td class=\"\\w+\" align=\"\\w+\">(\\d+\\w+, ?)+(\\d+\\w+,? ?)*(Q\\d+,? ?)*<\\/td>", ""); // we don't need "Betroffene Klassen" contents (though this regex is quite broken)
        html = html.replaceAll("<br>", " "); // <br> tags confuse Reader
        html = html.replaceAll("<strike.*>.+</strike>", "---"); // strike tags also confuse Reader


        // get an InputStream that contains String
        InputStream in = null;
        try {
            in = new ByteArrayInputStream(html.getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return;
        }

        // create parser
        try {
            mParser = Xml.newPullParser();
            mParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);

            mParser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true); // because the meta tag is not closed
            mParser.setInput(in, null);
            mParser.nextTag();


            in.close();
        } catch (XmlPullParserException | IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void addEntries() {
        try {

            // just some initialising
            String previousStartTag = "null";
            String previousEndTag = "null";
            boolean writeBecauseTrtd = false;
            boolean insideDateTag = false;
            boolean blockWriteBecauseNoPage = false;
            String date;


            while (true) {


                switch (mParser.next()) {
                    case XmlPullParser.START_TAG:

                        if (previousStartTag.equals("tr") && mParser.getName().equals("td")) {
                            writeBecauseTrtd = true;
                        }

                        if (mParser.getName().equals("div")) {
                            insideDateTag = true;
                        }

                        previousStartTag = mParser.getName();

                        break;


                    case XmlPullParser.TEXT:


                        if (writeBecauseTrtd && !blockWriteBecauseNoPage) {
                            if (mParser.getText().equals("Untis")) {
                                // "Page" is over
                                date = "";

                                blockWriteBecauseNoPage = true;
                            } else {


                                addToTable(mParser.getText());
                            }
                        }

                        if (insideDateTag) {
                            // save date
                            date = mParser.getText();

                            // build nice-looking date
                            String weekday = date.replaceFirst("\\d+.\\d+.\\d+ ", "");
                            weekday = weekday.replaceFirst(" \\(Seite \\d+ / \\d+\\)", "");

                            date = date.replaceFirst(" \\w+( \\(Seite \\d+ / \\d+\\))*", "");

                            // save date in table
                            addToTable(DATEMARKER + date);

                            // entering page, unblock
                            blockWriteBecauseNoPage = false;
                        }

                        break;


                    case XmlPullParser.END_TAG:

                        if (previousEndTag.equals("td") && mParser.getName().equals("tr")) {
                            writeBecauseTrtd = false;
                            addToTable("");
                        }

                        if (mParser.getName().equals("div")) {
                            insideDateTag = false;
                        }

                        previousEndTag = mParser.getName();

                        break;
                    case XmlPullParser.END_DOCUMENT:
                        interpretTableStrings();
                }
            }


        } catch (XmlPullParserException | IOException e) {
            e.printStackTrace();
        }
    }

    @Nullable
    @Override
    public String getSchoolName() {
        return null;
    }

    private void interpretTableStrings() {

        int consecutiveFilledLines = 0;
        Date date = null; // this field is filled in before Entries are created

        for (int i = 0; i < mTableStrings.size(); i++) {
            String s = mTableStrings.get(i);

            if (s.contains(DATEMARKER)) { // check whether it is a date line
                String[] dateDigits = s.replace(DATEMARKER, "").split("\\.");
                date = new Date(Integer.parseInt(dateDigits[2]) - 1900 /* years start at 1900 */, Integer.parseInt(dateDigits[1]) - 1 /* months start with 0 */,
                        Integer.parseInt(dateDigits[0])); // because SimpleDateTime did deliver good results. oh why
            } else if (!s.contains("&nbsp;") && !s.equals("")) {
                consecutiveFilledLines++;

                if (consecutiveFilledLines == 4) {
                    // if this is the fourth consecutive line

                    // get all the fields
                    String affectedClass = mTableStrings.get(i - 3);
                    String lesson = mTableStrings.get(i - 2);
                    String replacement = mTableStrings.get(i - 1);
                    String info = mTableStrings.get(i);

                    // create Entry
                    addEntry(affectedClass, lesson, replacement, info, date);


                    consecutiveFilledLines = -1; // cooldown
                }
            } else {
                if (consecutiveFilledLines == 3) {
                    // previous line was the third consecutive line
                    // get all the fields
                    String affectedClass = mTableStrings.get(i - 3);
                    String lesson = mTableStrings.get(i - 2);
                    String replacement = mTableStrings.get(i - 1);
                    String info = "";

                    // create Entry
                    addEntry(affectedClass, lesson, replacement, info, date);


                } else if (consecutiveFilledLines == 1) {
                    // there was just one line
                    // get all the fields
                    String affectedClass = "";
                    String lesson = "";
                    String replacement = "";
                    String info = mTableStrings.get(i - 1);

                    // create Entry
                    addEntry(affectedClass, lesson, replacement, info, date);


                } else if (consecutiveFilledLines == 2) {
                    // two separate lines are required
                    // get all the fields

                    // create Entries
                    addEntry("", "", "", mTableStrings.get(i - 2), date);
                    //addEntry("", "", "", mTableStrings.get(i - 1), date);


                }

                consecutiveFilledLines = 0;
            }
        }

    }

    private void addToTable(String s) {
        mTableStrings.add(s);
    }

}
